package cn.hdu.liang.ch6;

import cn.hdu.liang.ch4.Dish;

import java.util.*;
import java.util.stream.Collector;

import static cn.hdu.liang.ch4.Dish.menu;
import static java.util.stream.Collectors.*;

public class Grouping {

    public static void main(String[] args) {

        Map<Dish.Type, List<Dish>> dishesByType = menu.stream().collect(groupingBy(Dish::getType));
        System.out.println(dishesByType);

        Map<CaloricLevel, List<Dish>> dishesByCaLevel =
                menu.stream().collect(groupingBy(Grouping::getCaloricLevel));
        System.out.println(dishesByCaLevel);

        Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaLevel =
                menu.stream().collect(
                        groupingBy(Dish::getType,
                                groupingBy(Grouping::getCaloricLevel))
                );
        System.out.println(dishesByTypeCaLevel);

        Map<Dish.Type, Long> typesCount = menu.stream().collect(groupingBy(Dish::getType, counting()));
        System.out.println(typesCount);

        Map<Dish.Type, Optional<Dish>> mostCaByType = menu.stream()
                .collect(groupingBy(Dish::getType, maxBy(Comparator.comparing(Dish::getCalories))));
        System.out.println(mostCaByType);

        Map<Dish.Type, Dish> mostCaByType2 = menu.stream()
                .collect(groupingBy(Dish::getType,
                        collectingAndThen(maxBy(Comparator.comparing(Dish::getCalories)), Optional::get)));
        System.out.println(mostCaByType2);

        Map<Dish.Type, IntSummaryStatistics> totalCaByType = menu.stream()
                .collect(groupingBy(Dish::getType, summarizingInt(Dish::getCalories)));
        System.out.println(totalCaByType);

        Collector<Dish, ?, Set<CaloricLevel>> levelCollector = mapping(Grouping::getCaloricLevel, toSet());
        Map<Dish.Type, Set<CaloricLevel>> caLevelsByType = menu.stream()
                .collect(groupingBy(Dish::getType, levelCollector));
        System.out.println(caLevelsByType);

        Collector<Dish, ?, HashSet<CaloricLevel>> levelCollector2 =
                mapping(Grouping::getCaloricLevel, toCollection(HashSet::new));
        Map<Dish.Type, HashSet<CaloricLevel>> caLevelsByType2 = menu.stream()
                .collect(groupingBy(Dish::getType, levelCollector2));
        System.out.println(caLevelsByType2);

    }

    private static CaloricLevel getCaloricLevel(Dish dish) {
        if(dish.getCalories() <= 400) {
            return CaloricLevel.DIET;
        } else if(dish.getCalories() <= 700) {
            return CaloricLevel.NORMAL;
        } else {
            return CaloricLevel.FAT;
        }
    }
}
